﻿using mozhi.smarterp.Finance.Basedatas;
using mozhi.smarterp.Finance.Basedatas.Repository;
using mozhi.smarterp.Finance.Basedatas.Services;
using mozhi.smarterp.Finance.Querys;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.Guids;
using Volo.Abp.ObjectMapping;

namespace mozhi.smarterp.Finance.Tags
{
    public class TagAppService : BaseDataAppService<Tag, TagDto, TagCreateDto, TagUpdateDto>, ITagAppService
    {
        private TagManager _manager;

        private ITagRepository _tagRepository;

        public TagAppService(ITagRepository repository, IDataAssociationRepository dataAssociationRepository, IGuidGenerator guidGenerator, TagManager manager , IDistributedEventBus distributedEventBus)
            : base(repository, dataAssociationRepository, guidGenerator, distributedEventBus)
        {
            _manager = manager;
            _tagRepository = repository;
        }

        public new async Task<PagedResultDto<TagDto>> FindAsync(PageQuery query)
        {
            var entities = await _repository.FindAsync(query);

            var count = await _repository.GetCountAsync(query);

            var result = new PagedResultDto<TagDto>();

            var items = ObjectMapper.Map<List<Tag>, List<TagDto>>(entities);

            result.TotalCount = count;
            result.Items = items as IReadOnlyList<TagDto>;

            return result;
        }

        public new async Task<TagDto> GetAsync(Guid id)
        {
            var tag = await _repository.FindAsync(id);

            return ObjectMapper.Map<Tag, TagDto>(tag);
        }

        public override async Task<TagDto> CreateAsync(TagCreateDto dto)
        {
            await Validate(null, dto.Code, dto.Name);

            var tag = new Tag(_guidGenerator.Create(), dto.Code, dto.Name, dto.Type);

            var tagItems = new List<TagItem>();

            dto.Items?.ForEach(x =>
            {
                var item = new TagItem(_guidGenerator.Create(), x.Code, x.Name);

                tagItems.Add(item);
            });

            tag.ChangeItems(tagItems);

            tag.ChangeType(dto.Type);

            tag = await _repository.InsertAsync(tag);

            return ObjectMapper.Map<Tag, TagDto>(tag);
        }

        public override async Task<TagDto> UpdateAsync(TagUpdateDto dto)
        {
            await Validate(dto.Id, dto.Code, dto.Name);

            var tag = await _repository.GetAsync(dto.Id);

            if (tag == null)
                throw new UserFriendlyException("标签不存在", "100000");

            tag.Change(dto.Code, dto.Name, dto.Activated);

            var tagItems = new List<TagItem>();

            dto.Items?.ForEach(x =>
            {
                var item = new TagItem(x.Id ?? _guidGenerator.Create(), x.Code, x.Name);

                tagItems.Add(item);
            });

            tag.ChangeItems(tagItems);

            await _manager.ChangeType(tag, dto.Type);

            tag = await _repository.UpdateAsync(tag);

            return ObjectMapper.Map<Tag, TagDto>(tag);

        }

        public async Task<bool> DeleteItemAsync(Guid id, Guid itemId)
        {
            var tag = await _repository.GetAsync(id);

            if (tag == null)
                throw new UserFriendlyException("标签不存在", "100000");

            var matchItem = tag.Items?.FirstOrDefault(x => x.Id == itemId);

            if (matchItem == null)
                throw new UserFriendlyException("标签项目不存在", "100000");

            await _manager.RemoveItem(tag, matchItem);

            return true;
        }

        public async Task<List<TagItemDto>> FindItemAsync(Guid tagId, PageQuery query)
        {
            var tagItems = await _tagRepository.FindItemsAsync(tagId, query);

            var result = ObjectMapper.Map<List<TagItem>, List<TagItemDto>>(tagItems);

            return result;
        }
    }
}
